2023春哈工大CSAPP大作业 您所在的位置:网站首页 DCA决策曲线 R语言 2023春哈工大CSAPP大作业

2023春哈工大CSAPP大作业

2023-06-02 18:13| 来源: 网络整理| 查看: 265

计算机系统

大作业

题     目  程序人生-Hello’s P2P

专       业      网络空间安全       

学     号      2021112406         

班   级       2103901           

学       生       刘晓赟            

指 导 教 师        吴锐              

计算机科学与技术学院

2023年5月

摘  要

通过各种工具,结合计算机系统的知识,对hello.c的一生进行分析:预处理、编译、汇编、链接成为可执行文件程序到载入内存、成为进程,再到执行完毕、内存回收。本次大作业以hello.c为源文件。

关键词:计算机系统;预处理;编译;汇编;链接;进程;存储;I/O 管理                           

目  录

第1章 概述

1.1 Hello简介

1.2 环境与工具

1.3 中间结果

1.4 本章小结

第2章 预处理

2.1 预处理的概念与作用

2.2在Ubuntu下预处理的命令

2.3 Hello的预处理结果解析

2.4 本章小结

第3章 编译

3.1 编译的概念与作用

3.2 在Ubuntu下编译的命令

3.3 Hello的编译结果解析

3.4 本章小结

第4章 汇编

4.1 汇编的概念与作用

4.2 在Ubuntu下汇编的命令

4.3 可重定位目标elf格式

4.4 Hello.o的结果解析

4.5 本章小结

第5章 链接

5.1 链接的概念与作用

5.2 在Ubuntu下链接的命令

5.3 可执行目标文件hello的格式

5.4 hello的虚拟地址空间

5.5 链接的重定位过程分析

5.6 hello的执行流程

5.7 Hello的动态链接分析

5.8 本章小结

第6章 hello进程管理

6.1 进程的概念与作用

6.2 简述壳Shell-bash的作用与处理流程

6.3 Hello的fork进程创建过程

6.4 Hello的execve过程

6.5 Hello的进程执行

6.6 hello的异常与信号处理

6.7本章小结

第7章 hello的存储管理

7.1 hello的存储器地址空间

7.2 Intel逻辑地址到线性地址的变换-段式管理

7.3 Hello的线性地址到物理地址的变换-页式管理

7.4 TLB与四级页表支持下的VA到PA的变换

7.5 三级Cache支持下的物理内存访问

7.6 hello进程fork时的内存映射

7.7 hello进程execve时的内存映射

7.8 缺页故障与缺页中断处理

7.9动态存储分配管理

7.10本章小结

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

8.2 简述Unix IO接口及其函数

8.3 printf的实现分析

8.4 getchar的实现分析

8.5本章小结

结论

附件

参考文献

第1章 概述 1.1 Hello简介

P2P:

 hello.c文件要通过编译系统变换为hello可执行程序。首先hello.c文件经过cpp预处理器得到文本文件hello.i,之后经过ccl编译器生成汇编程序hello.s,接着再经过as汇编器生成可重定位目标程序hello.o,最后经过ld链接器,与其它用到的库函数可重定位文件链接,生成可执行程序hello

O2O:

O2O程序并不是一开始就在内存空间中的,也就是一开始为0。OS为hello fork一个子进程,然后在execve执行hello程序,OS会为他开辟一个块虚拟内存,并将程序加载到虚拟内存映射到的物理内存中。当程序执行完,OS回收这一程序,同时为该程序的开辟的内存空间也会被回收,此时又变为0。

1.2 环境与工具

1.2.1 硬件环境

      Windows10

X64 CPU;2GHz;2G RAM;256GHD Disk 以上1.2.2 软件环境

1.2.2 软件环境

      Vmware 17pro

1.2.3 开发工具

Visual Studio 2022 64位

1.3 中间结果

文件名

作用

hello.c

源程序

hello.i

预处理文件

hello.s

汇编文件

hello.o

可重定位目标文件

hello

可执行文件

hello_asm.txt

hello的反汇编文件

hello_o_astm.txt

hello.o的反汇编文件

hello_o.elf

hello.o的ELF格式文件

hello.elf

hello的ELF格式文件

1.4 本章小结

        简单介绍hello的p2p和o2o概念,列出过程文件。

第2章 预处理 2.1 预处理的概念与作用

概念:预处理是在将程序源代码转换为目标代码时生成二进制代码之前的过程。它的作用通常包括拆分源代码、删除注释、替换宏和包以及处理各种预编译指令。

作用:有多种预处理指令,主要包括#if(条件编译)、#define(宏定义)、#include(源文件包含)、#line(行控制)、#error(错误指令)等等,预处理可以使源代码在不同的执行环境中被方便地修改、移植和调试,也有利于阅读和模块化程序设计。

2.2在Ubuntu下预处理的命令

                                                         图 1 hello.c进行预处理

2.3 Hello的预处理结果解析

由图2和图3对比,经过预处理过后,程序由原来的23行扩展到了3091行。而在hello.c中的代码注释已被删去,其声明引用的各种头文件也按顺序被读取使用。

图 2 hello.c和hello.i开头部分

图 3hello.c和hello.i尾部

2.4 本章小结

本章主要介绍了预处理的概念以及作用,并对预处理结果进行了分析。

第3章 编译 3.1 编译的概念与作用

    概念:编译是指使用编译器将用源语言编写的源程序转换为目标程序的过程,即将源语言翻译成计算机可以识别的二进制语言的过程。    

 作用:将源语言转换为汇编语言,为后续过程做准备。

3.2 在Ubuntu下编译的命令

图 4 编译生成hello.s

3.3 Hello的编译结果解析

     3.3.1局部变量int

局部变量会储存在栈中。如图5所示:当进入main函数后,先声明了一个int类型的局部变量,但没有初始化。通过移动栈指针申请空间存储局部变量,运行之后会被释放。

图 5

 3.3.2字符串常量

 字符串常量在hello.s最开头.rodata的LC0与LC1处已被储存,且标记为只读数据,当在函数中使用这些字符串常量时,将使用字符串对应的地址来防止字符串数据被修改。如图6中展示了第一个printf里的字符串。

图 6

 3.3.3赋值操作

     主要是数据传送指令(MOV类),如图7展示了for循环i=0的操作。

图 7

 3.3.4关系操作

  关系操作通过CMP指令与其他指令共同配合完成,图8展示了 “ hello_o.elf可得到hello_o.elf,图13较为详细地介绍了elf格式的内容。

4.3.2 ELF头

ELF 头描述文件的整体格式。它从一个 16 字节序列开始,描述生成文件的系统的单词的大小和字节顺序,其余部分包括 ELF 头的大小、目标文件的类型、机器类型、节头部表的文件偏移量以及节头部表中条目的大小和数量, 这可以帮助链接器解析和解释目标文件的信息。

图 13 ELF头

      4.3.3节头部表

     描述目标文件的节,它描述了不同节的名字、类型、位置和大小。

图 14 节头部表

     4.3.4可重定位节和符号表

.rel.text是一个.text节中位置的列表,链接器把这个目标文件和其它文件组合时,需要修改这些位置。.symtab表示符号表,它存放在程序中定义和引用的函数和全局变量的信息。(如图15所示)

图 15 可重定位节和符号表

4.4 Hello.o的结果解析

4.4.1机器指令

命令:objdump -s -d hello.o > hello_o_asm.txt(结果如图16)

图 16

对比hello_o_asm.txt文件和hello.s,差别不大,但反汇编文件有机器指令,由操作码和地址码构成,每条机器指令最前面有指令的相对地址。

图 17 hello.s(左),hello_o_asm.txt(右)

 4.4.2函数调用

 hello.s文件中,函数调用的具体目的地是用函数名给出的,因为调用的函数还在其它库中,其具体调用的地址无法确定,只有在经过链接后函数调用的准确位置才能确定(如图18)。

图 18 函数调用

  4.4.3分支跳转

  hello.o中分支跳转目的地是段名给出,汇编后分支跳转是有明确的地址偏移。

图 19 分支跳转对比

4.5 本章小结

本章介绍了汇编的概念和作用,以hello.o程序和反汇编对对比,详细分析汇编前后程序的变化(不同),对产生的可重定位目标文件的理解,同时对函数调用和分支跳转的地址转移(偏移)做了工作,方便链接器的链接。

第5章 链接 5.1 链接的概念与作用

概念:将源代码文件中的多个目标文件(object file)或库文件(library file)连接成一个可执行文件(executable file)的过程。

作用:链接器在编译后的多个目标文件间进行连接,使得我们的程序能够被执行。同时也可以将符号定义和符号引用进行匹配,减小可执行文件大小,提高代码复用性等。

5.2 在Ubuntu下链接的命令

链接的命令:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o hello.o -lc /usr/lib/gcc/x86_64-linux-gnu/7/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o -z relro -o hello

图 20 链接生成helo

5.3 可执行目标文件hello的格式

5.3.1可执行文件

命令:readelf -a hello > hello.elf生成hello.elf文件。

图 21 ELF可执行目标文件

5.3.2 ELF头

ELF头记录了记录了文件的类型,版本信息,段表文件偏移、节表文件偏移,程序入口点等信息。其中标识为exec表明为可执行目标文件。

图 22 ELF头

5.3.3节头部表

描述节的类型、大小、位置和名字等等,hello节头部表比hello.o节头部表多了   许多信息

图 23 ELF节头部表

5.3.4 程序头部表

是 ELF 格式文件中的一个数据结构,存储着可执行文件或共享库文件的程序头部信息。每个 ELF 格式文件都有一个程序头部表,而不是单独的程序头部。

图 24 程序头部表

5.4 hello的虚拟地址空间

在edb加载hello

图 25 edb加载hello

由5.3中各段的起始地址,可以在data dump中查看相应段。以.text段为例,其在节头部表中的信息为:

图 26  .text在节头部表的信息

由此可得其起始地址为0x4004e0,大小为0x1f2字节,在data dump中找到其对应的内容为:

图 27 .text对应内容

5.5 链接的重定位过程分析

5.5.1 hello和hello.o

命令:objdump –d hello > hello_asm.txt生成hello反汇编文件。比较发现不同之处:

hello文件中增加了链接之后增加的函数,这些函数都是hello所调用的。hello文件中增加了.init节和.plt节。hello文件中所有的地址都被替换成了运行是的实际地址,hello.o文件中的地址都是从0开始的。

5.5.2重定位过程

重定位项目的格式为:

typedef struct{

       long offset;       //需要被修改的引用的节偏移

       long type:32;    //重定位类型

       symbol:32; //被修改的引用指向的符号

       long addend;     //偏移调整量

}Elf64_Rela;

在重定位过程中,链接器根据重定位类型的不同得到不同的便宜调整量,通过节偏移和重定位条目的地址就可以计算出重定位后的地址;最基本的重定位类型有两种,分别是重定位一个使用32位PC相对地址的引用和重定位一个使用32位绝对地址的引用。

5.6 hello的执行流程

子程序名

程序地址

_init

0x401000

puts@plt

0x401090

printf@plt

0x4010a0

getchar@plt

0x4010b0

atoi@plt

0x4010c0

exit@plt

0x4010d0

sleep@plt

0x4010e0

_start

0x4010f0

_dl_relocate_static_pie

0x401120

main

0x40112d

_fini

0x4011b4

5.7 Hello的动态链接分析

   在调用共享库函数时,编译器没有办法预测这个函数的运行时地址,因为定义它的共享模块在运行时可以加载到任意位置。正常的方法是为该引用生成一条重定位记录,然后动态链接器在程序加载的时候再解析它;GNU编译系统使用延迟绑定,将过程地址的绑定推迟到第一次调用该过程时。

在节头部表中查看GOT的起始地址:

图 28 GOT起始地址

在edb中查看GOT的内容:

图 29 在edbGOT

在dl_init之后再次查看GOT内容:

图 30 dl_init之后的GOT内容

发现0x601008和0x601010两个字节发生变化,出现了两个地址:

0x7f7f256f8170和0x7f7f254e4820,这就是GOT[1]和GOT[2]的地址。

5.8 本章小结

      本章介绍了链接的概念与作用,通过查看虚拟地址,对比分析反汇编代码等一系列过程,加深了对重定位、执行流程、动态链接的理解。

第6章 hello进程管理 6.1 进程的概念与作用

概念:进程是计算机中正在执行的程序的实体。一个程序被加载进计算机的内存中时,就形成了它对应的进程。

作用:为操作系统提供了多任务并发处理、进程间通信和同步、稳定性和安全性以及高级程序开发+抽象等方面的支持。

6.2 简述壳Shell-bash的作用与处理流程

作用:壳(shell)是一种命令语言解释器,它是用户与操作系统之间的接口,通过shell,用户可以向操作系统发出各种命令和指令来执行某些操作或完成某些任务。

处理流程:

读取用户输入的命令行,用解析器将命令行中的命令和参数解析出来。对解析出来的命令和参数进行拓展处理。例如,将变量替换为其所代表的值,将通配符展开为其(们)所匹配的文件名等。编译命令。将处理后的命令行转化为可执行代码。执行编译后的命令行。Bash创建一个子进程,在其中执行编译后的命令行,并将结果呈现给用户。执行完毕后,将子进程退出。 6.3 Hello的fork进程创建过程

hello的fork()创建一个新的进程,称为子进程,在此进程中复制父进程的内容和状态。子进程就像一个全新的进程,拥有自己的进程ID(PID),并在自己的地址空间中复制父进程的代码段、数据段和堆栈段等信息。因此,子进程可以像父进程一样执行代码和访问数据,但它拥有自己独立的内存空间。

当父进程调用fork()时,操作系统会创建一个完全相同的子进程,并将子进程的 PID 返回给父进程。子进程的代码从 fork() 返回的位置开始执行,这样父子进程之间便可以并发运行,其中子进程是父进程的副本。

6.4 Hello的execve过程

execve函数在当前进程下的上下文中加载并运行一个新程序。函数声明如下:

int execve(const char *filename, const char *argv[], const char *envp[]);

它加载并运行一个可执行目标文件filename,且带参数列表argv和环境变量列表envp,期间会调用一个加载器,它会将创建内存映像并将可执行文件的片复制到代码段和数据段。之后,加载器会跳转到_start函数的地址点来设置用户栈(图31介绍一种典型的用户栈),最后将控制权交给main函数。

图 31 典型的用户栈

6.5 Hello的进程执行

由于系统一般会运行多个进程,所以处理器的物理控制流就会被分成多个逻辑控制流。由于进程间轮流使用处理器,内核为每个进程会维持一个上下文,上下文信息就是内核重新启动一个被抢占的进程所需要而定状态,由一些对象的值组成,包括寄存器、程序计数器、用户栈等。而进城间的上下文切换模式如图32所示。其中,进程执行他的控制流的一部分的每一时间段都叫作“控制流时间片”。

图 32 上下文切换

  在hello程序中,上下文切换和进程调度主要发生在sleep函数处,执行sleep前hello进程会处于用户模式并顺序执行,当执行sleep函数以后会被切换到到内核模式进入休眠,加入等待序列;当休眠结束后引起中断并切换到用户模式执行被挂起的程序,直至下次上下文切换。

6.6 hello的异常与信号处理

6.6.1可能出现的异常:

异常可以分为四类:中断、陷阱、故障和终止(如图33)

图 33 异常情况

6.6.2hello执行时的异常

正常情况:执行hello程序时,在hello进程结束后,hello进程会变为僵死进程并向父进程Shell发送SIGCHLD信号,父进程Shell会完成hello进程的回收工作。

运行时乱按或回车

如图34在程序执行过程中乱按或输入回车。hello程序运行不受影响,待其运行结束后命令行处理这些回车和字符。

图 34 程序执行时乱按或回车

运行时输入Ctrl+C

程序运行时输入Ctrl-C会导致进程立即终止,因为Ctrl-C会发送一个SIGINT信号给hello进程,而SIGINT信号的默认操作是终止进程,因此终止处理程序会立即终止进程。如图35。

图 35 程序执行时按Ctrl+C

运行时输入Ctrl+Z

进程挂起,接下来执行ps、jobs、pstree、fg、kill命令:

ps:

图 36 ps

jobs:列出当前工作集中的工作

图 37 jobs

pstree:打印进程树

图 38 pstree

fg:从头运行一遍

kill:向进程发信号,先用ctrl+Z挂起进程,再用ps查询hello的PID为6972,输入指令kill -9 6972将hello进程关闭

图 39 用kill给进程发信号

6.7本章小结

本章介绍了进程的概念和进程的作用,简述了shell的作用和处理流程,并详细介绍了fork进程创建的过程和execve进程加载的过程,同时分析了hello的进程执行,以及执行过程中遇到的异常和信号及相应处理。通过这一章,我们更深入得认识了hello函数在进程中的表现。

第7章 hello的存储管理 7.1 hello的存储器地址空间

7.1.1逻辑地址

逻辑地址是进程在执行时使用的虚拟地址,是一个虚拟的地址空间。在操作系统内部,逻辑地址会经过内存管理单元(MMU)进行地址映射的转换,映射为实际的物理地址,它由一个段标识符(Segment Selector)加上一个指定段内相对地址的偏移量(offset)组成的。

7.1.2虚拟地址

虚拟地址是由操作系统分配给应用程序使用的地址,其实就是逻辑地址的段内偏移offset。

7.1.3线性地址

线性地址指的是虚拟地址到物理地址变换之间的中间层。CPU将逻辑地址中的段选择器和描述符中的信息结合起来,就可以得到线性地址。

7.1.4物理地址

物理地址是指计算机系统中内存单元的实际地址,是处理器(CPU)直接访问内存单时所使用的地址。与虚拟地址相对应,物理地址是指内存地址在物理上的实际位置,以字节为单位进行编号。 

7.2 Intel逻辑地址到线性地址的变换-段式管理

使用段式管理来实现逻辑地址到线性地址的转换。它将线性地址划分为段选择子和段内偏移量两部分,其中段选择子用于索引描述符表,以获取一个描述符,该描述符包含了表述段的信息。描述符主要包括段基址、段限制、段访问权限等信息。根据这些描述符信息,CPU 可以将逻辑地址转换为线性地址。

7.3 Hello的线性地址到物理地址的变换-页式管理

在页式管理中,线性地址被划分为两部分:页目录项索引和页表项索引。页目录表和页表分别存储页目录项和页表项,每一项包含了一个物理页框的起始地址以及该页的属性。页目录项索引和页表项索引组成了一个两级的查找结构,通过这个结构可以找到相应的物理地址(如图40)。

图 40 页式管理

7.4 TLB与四级页表支持下的VA到PA的变换

使用TLB时,首先会查找相应的组索引中是否有相应的条目,若没有则会按照一定策略进行条目替换。

而四级页表将逻辑地址分成四部分:页表索引、页目录索引、页目录表索引和页全局目录偏移量。CPU首先访问页全局目录(PGD)在内存中的地址,根据页全局目录偏移量找到页目录表。在四级页表的规格下,虚拟地址被分为了4个VPN和1个VPO,根据VPN依次访问各级页表就可以找到对应的PPN,进而实现物理地址的寻址。(如图41结合四级页表和TLB)

图 41 结合四级页表和TLB

7.5 三级Cache支持下的物理内存访问

三级高速缓存(L1、L2和L3)内存组成层次结构,根据存储器距离CPU的远近以及访问速度的快慢,从而提升CPU访问内存的速和效率。当CPU访问内存时,如果目标内存地址位于L1缓存中,则直接从L1中读取数据。如果地址不在L1缓存中,则将请求转发到L2缓存,此过程重复进行,直到数据在L1、L2或L3缓存中被发现为止。如果三级缓存都未找到所需数据,则需从存中检索。     当内存请求被发送到L3缓存时,逻辑类似,直到当数据被检索并保存在L3或L2缓存中时,最终数据将被传输到L1缓存,并交付给CPU(如图42)。

图 42 三级Cache

7.6 hello进程fork时的内存映射

Linux通过将虚拟内存区域与磁盘上的对象关联起来以初始化这个虚拟内存区域的内容,这个过程称为内存映射。

当fork被hello进程调用后,内核会为新进程创建各种数据,并分配给他一个唯一的PID。它将为两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时复制。当fork在新进程中返回时,新进程现在的虚拟内存刚好和调用fork函数时存在的虚拟内存相同。当两个进程中的任一个后来进行写操作时,写时复制机制就会创建新页面,如图43。

图 43 私有的写时复制

7.7 hello进程execve时的内存映射

运行hello程序在调用fork函数创建新子进程及对应的虚拟内存后,execve加载并运行hello.out需要几个步骤,内存映射示意如图44所示。

删除已存在的用户区域创建新的区域结构设置PC,指向代码区域的入口点

图 44 调用execve的内存映射

7.8 缺页故障与缺页中断处理

DRAM缓存不命中称为缺页,若程序运行需要的数据和代码未从磁盘加载到内存,就会发生缺页故障。

缺页过程及中断处理:

处理器将虚拟地址发送给 MMUMMU 使用内存中的页表生成PTE地址有效位为零, 因此 MMU 触发缺页异常缺页处理程序确定物理内存中牺牲页 (若页面被修改,则换出到磁盘)缺页处理程序调入新的页面,并更新内存中的PTE缺页处理程序返回到原来进程,再次执行导致缺页的指令

图 45 缺页故障和处理

7.9动态存储分配管理

动态内存管理是指在运行程序时,按照程序的需要分配和释放内存空间。C语言中提供了一些动态内存分配函数来实现动态内存管理,其中包括malloc和free等函数。

基本的动态内存管理方法是通过调用malloc函数在堆空间中分配一块连续的内存空间,并将其地址返回给调用函数。程序通过指针变量引用这块内存空间,使用完后则调用free函数将其释放,归还给系统。

动态内存管理策略主要包括内存分配算法和内存回收算法,这两者决定了动态分配内存的过程(如图46动态存储分配)

图 46 动态存储分配

7.10本章小结

本章主要介绍了hello的存储管理,先介绍了如何由指令的虚拟地址从逻辑地址通过段式管理转化到线性地址,再通过页式管理转化到物理地址。之后介绍具体的访存策略,包括四级页表、TLB和三级Cache等等。最后介绍了hello程序如何处理缺页故障异常和实现动态存储分配管理。

第8章 hello的IO管理 8.1 Linux的IO设备管理方法

(以下格式自行编排,编辑时删除)

设备的模型化:文件

设备管理:unix io接口

8.2 简述Unix IO接口及其函数

(以下格式自行编排,编辑时删除)

8.3 printf的实现分析

(以下格式自行编排,编辑时删除)

https://www.cnblogs.com/pianist/p/3315801.html

从vsprintf生成显示信息,到write系统函数,到陷阱-系统调用 int 0x80或syscall等.

字符显示驱动子程序:从ASCII到字模库到显示vram(存储每一个点的RGB颜色信息)。

显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

(以下格式自行编排,编辑时删除)

异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。

getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。

8.5本章小结

(以下格式自行编排,编辑时删除)

(第8章1分)

结论

hello的一生:

预处理:预处理器预处理hello.c源程序,得到hello.i。编译:编译器编译hello.i文件,得到汇编程序hello.s。汇编:汇编器汇编hello.s文件,得到可重定位目标程序hello.o。链接:链接器将hello.o文件与库函数链接,得到可执行目标文件hello。创建进程:在shell中运行hello,shell为hello创建子进程。加载进程:子进程中调用execve函数,加载并运行hello。执行指令:hello进程顺序执行指令,对遇到的异常和信号做出反应。回收进程:hello执行结束后,shell回收进程,系统释放进程占用的内存。

 hello的一生承载着我对计算机系统这门课程三个多月的学习记忆,同时也有些遗憾没有将CSAPP真正学透彻,希望我可以一步一个脚印,继续学习计算机系统领域的知识。

附件

文件名

作用

hello.c

源程序

hello.i

预处理文件

hello.s

汇编文件

hello.o

可重定位目标文件

hello

可执行文件

hello_asm.txt

hello的反汇编文件

hello_o_astm.txt

hello.o的反汇编文件

hello_o.elf

hello.o的ELF格式文件

hello.elf

hello的ELF格式文件

参考文献   百度百科  CSAPP课程pdf:《第6章 存储器层次系统2》

《第7章 链接》

《第8章 异常控制流II-信号(new)》

《第8章 异常控制流I-异常和进程》

《第9章 虚拟内存I-概念与系统》



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有